package org.gap.wizards.world;

import static org.gap.wizards.world.ClosedSpace.DoorState.CLOSED;
import static org.gap.wizards.world.ClosedSpace.DoorState.OPEN;

import java.awt.Point;
import java.awt.Rectangle;

import org.gap.wizards.utils.Persistable;
import org.gap.wizards.utils.Persistence;
import org.gap.wizards.views.ViewPlatform;
import org.gap.wizards.views.ViewPlatform.Color;

public class ClosedSpace implements Persistable {
	private static final String DOOR = "door";
	private static final String DIMENSIONS = "dimensions";
	private static final String LOCATION = "location";

	enum DoorState {
		CLOSED(false, '+'), OPEN(true, '/');
		
		private final boolean isOpen;
		private final char drawAs;

		DoorState(boolean isOpen, char drawAs) {
			this.isOpen = isOpen;
			this.drawAs = drawAs;
		}
		
		boolean isOpen() {
			return isOpen;
		}
		
		String drawAs() {
			return "" + drawAs;
		}
	};
	
	private static final int CORRECT_FOR_STARTING_AXIS = -1;
	private Rectangle rectangle;
	private Point door;
	private DoorState doorState = CLOSED;

	public ClosedSpace(Rectangle rectangle, Point door) {
		this.rectangle = rectangle;
		this.door = door;
	}

	public ClosedSpace() {
	}

	public boolean canMoveTo(Point location) {
		if (location.equals(door)) {
			return doorState.isOpen();
		}
		if ((location.x == rectangle.x || location.x == rectangle.x + rectangle.width + CORRECT_FOR_STARTING_AXIS) &&
				(isBetween(location.y, rectangle.y, rectangle.height))) {
			return false;
		} else if ((location.y == rectangle.y || location.y == rectangle.y + rectangle.height + CORRECT_FOR_STARTING_AXIS) &&
				(isBetween(location.x, rectangle.x, rectangle.width))) {
			return false;
		} else {
			return true;
		}
	}

	private boolean isBetween(int desiredAxis, int start, int length) {
		return desiredAxis >= start && desiredAxis <= start + length + CORRECT_FOR_STARTING_AXIS;
	}

	public void draw(ViewPlatform console) {
		for (int y = rectangle.y; y < rectangle.y + rectangle.height; y++) {
			String line = null;
			if (y == rectangle.y ) {
				line = drawNorthernWall(rectangle.x, y, rectangle.width);
			} else if (y == rectangle.y + rectangle.height - 1){
				line = drawSouthernWall(rectangle.x, y, rectangle.width);
			} else {
				line = drawVerticalWall(rectangle.x, y, rectangle.width);
			}
			console.print(rectangle.x, y, Color.GRAY, line);
		}
		console.print(door.x, door.y, Color.BROWN, doorState.drawAs());
	}

	private String drawNorthernWall(int x, int y, int width) {
		StringBuffer line = new StringBuffer(width);
		line.append((char)9484);
		for (int i = x + 1; i < x + width - 1; i++) {
			line.append((char)9472);
		}
		line.append((char)9488);
		return line.toString();
	}
	
	private String drawSouthernWall(int x, int y, int width) {
		StringBuffer line = new StringBuffer(width);
		line.append((char)9492);
		for (int i = x + 1; i < x + width - 1; i++) {
			line.append((char)9472);
		}
		line.append((char)9496);
		return line.toString();
	}

	private String drawVerticalWall(int x, int y, int width) {
		StringBuffer line = new StringBuffer(width);
		line.append((char)9474);
		for (int i = x + 1; i < x + width - 1; i++) {
			line.append('.');
		}
		line.append((char)9474);
		return line.toString();
	}

	public void open(Point door) {
		if (door.equals(this.door)) {
			doorState = OPEN;
		}
	}

	public void close(Point door2) {
		if (door.equals(this.door)) {
			doorState = CLOSED;
		}
	}

	public boolean contains(Point point) {
		return rectangle.contains(point);
	}
	
	@Override
	public void persist(Persistence persister) {
		persister.set(LOCATION, rectangle.getLocation());
		persister.set(DIMENSIONS, rectangle.getSize());
		persister.set(DOOR, door);
	}

	@Override
	public void load(Persistence persister) {
		rectangle = new Rectangle(
				persister.getPoint(LOCATION), 
				persister.getDimension(DIMENSIONS));
		door = persister.getPoint(DOOR);
	}
}
